package com.jplus.mvc.action.doorlock;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jplus.core.mvc.WebUtil;
import com.jplus.core.mvc.anno.PathVariable;
import com.jplus.core.mvc.anno.ReqeustBody;
import com.jplus.core.mvc.anno.RequestMapping;
import com.jplus.core.mvc.anno.RequestParam;
import com.jplus.core.mvc.anno.RestController;
import com.jplus.core.mvc.vo.Model;
import com.jplus.core.utill.JSON;
import com.jplus.core.utill.JUtil;
import com.jplus.core.utill.StreamUtil;
import com.jplus.mvc.util.AESUtil;
import com.jplus.mvc.util.DoolockCMD.ResetCommand;

@RestController
public class DoorLockAction {
	final Logger log = LoggerFactory.getLogger(DoorLockAction.class);

	public static void main(String[] args) throws IOException {
		String key = "1234567890123456";
		InputStream input = new URL("http://47.100.49.155/s/cmd/reset/" + key).openStream();
		System.out.println(new String(StreamUtil.toByteArray(input)));
	}

	@RequestMapping("/s/cmd/{type}/{key}")
	public void getCmd(@PathVariable("type") String type, @PathVariable("key") String key) {
		String res = "Request error, no instruction";
		if (key.length() == 16) {
			if (type.equals("reset"))
				res = JUtil.byte2Hex(AESUtil.encrypt(JUtil.hex2Bytes(new ResetCommand().build()), key.getBytes()));
		}
		WebUtil.writeTEXT(res);
	}

	@RequestMapping("/getinit")
	public Model getInit(HttpSession session) throws ParseException {
		InitLock lock = (InitLock) session.getAttribute("InitLock");
		if (lock == null)
			return new Model().FAIL().DATA("请先初始化");
		else
			return new Model().SUCC().DATA(lock);
	}

	@RequestMapping("/initlock")
	public Model initLock(@ReqeustBody InitLock lock, HttpSession session) {
		log.info("[session]:" + session.getId());
		if (!(lock.seed1 > 10000 && lock.seed2 > 10000 && lock.key.trim().length() == 16))
			return new Model().FAIL().DATA("参数异常");

		/**
		 * 该初始化在门锁初始化时执行
		 */
		int seed1 = lock.seed1;// 种子1
		int count1 = 87616;//
		RandomSequence seq1 = new RandomSequence(seed1);
		lock.sequenceHigh = seq1.getSequence(count1);

		int seed2 = lock.seed2;// 种子2
		int count2 = 97536;
		RandomSequence seq2 = new RandomSequence(seed2);
		lock.sequenceLow = seq2.getSequence(count2);
		log.info(lock.toString());
		session.setAttribute("InitLock", lock);

		return new Model().SUCC();
	}

	@RequestMapping("/buildPwd")
	public Model buildPwd(@ReqeustBody Pwd pwd, HttpSession session) {
		log.info("[session]:" + session.getId());
		try {
			InitLock lock = (InitLock) session.getAttribute("InitLock");
			if (lock == null)
				return new Model().FAIL().DATA("请先初始化");
			log.info(lock.toString());
			log.info(JSON.toJSONString(pwd));
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
			pwd.startHour = RandomCipherHelper.getLocalTimeHour(sdf.parse(pwd.startTime.substring(0, 16)));
			pwd.endHour = RandomCipherHelper.getLocalTimeHour(sdf.parse(pwd.endTime.substring(0, 16)));
			// == 生成密码 =======================================

			String pwdStart = RandomCipherHelper.computHighPwd(lock.sequenceHigh, lock.getInitHour(), pwd.startHour);
			log.info("H:" + pwdStart);
			List<Integer> pwdends = RandomCipherHelper.computLowPwd(lock.sequenceLow, pwd.startHour, pwd.endHour,
					pwd.type, pwd.loopStrategy, pwd.loopEndPoint);
			log.info("L:" + pwdends + "\t" + pwdends.size());
			int index = (int) (Math.random() * pwdends.size());// 随便取一个
			Integer pwdEnd = pwdends.get(index);
			String pwds = pwdStart + "" + pwdEnd;
			log.info("生成密码:" + pwds);

			// == 密码加密 =======================================
			AES10 aes10 = new AES10(lock.key.toCharArray(), lock.key.toCharArray());
			String aesPwd = new String(aes10.Encrypt(pwds.toCharArray(), pwds.length()));// 加密后
			String radPwd = new String(aes10.Decrypt(aesPwd.toCharArray(), aesPwd.length()));// 解密后
			log.info("AES密码 :" + aesPwd + "\t解密后：" + radPwd);
			// ==
			pwd.aesPwd = aesPwd;
			pwd.radPwd = radPwd;
			return new Model().SUCC().DATA(pwd);
		} catch (Exception e) {
			e.printStackTrace();
			return new Model().FAIL().DATA("参数异常");
		}
	}

	@RequestMapping("/verifyPwd")
	public Model verifyPwd(@RequestParam("pwd") String aesPwd, HttpSession session) {
		try {
			InitLock lock = (InitLock) session.getAttribute("InitLock");
			if (lock == null)
				return new Model().FAIL().DATA("请先初始化");
			AES10 aes10 = new AES10(lock.key.toCharArray(), lock.key.toCharArray());
			String radPwd = new String(aes10.Decrypt(aesPwd.toCharArray(), aesPwd.length()));// 解密后
			String pwdStart = radPwd.substring(0, 5);
			String pwdEnd = radPwd.substring(5);

			int p1 = (lock.sequenceHigh.get(Integer.parseInt(pwdStart)) + lock.getInitHour()); // 开始时间：到小时
			int p2 = lock.sequenceLow.get(Integer.parseInt(pwdEnd)) / 10; // 结束时间：小时偏移量
			int nowHour = RandomCipherHelper.getLocalTimeHour(new Date());
			int res = RandomCipherHelper.doParse(p1, p2, nowHour, aesPwd);
			return new Model().SUCC().DATA(aesPwd + "\n" + (res == 1 ? "密码校验成功，密码正确" : "密码校验失败，密码错误"));
		} catch (Exception e) {
			return new Model().SUCC().DATA(aesPwd + "\n" + "密码校验失败，密码错误\n" + e.getMessage());
		}
	}

	public static class InitLock {
		public String initTime;
		public int seed1;
		public int seed2;
		public String key = "";

		private List<Integer> sequenceHigh = new ArrayList<Integer>();
		private List<Integer> sequenceLow = new ArrayList<Integer>();

		public int getInitHour() throws ParseException {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
			return RandomCipherHelper.getLocalTimeHour(sdf.parse(initTime.substring(0, 16)));
		}

		@Override
		public String toString() {
			return "InitLock [initTime=" + initTime + ", seed1=" + seed1 + ", seed2=" + seed2 + ", key=" + key
					+ ", sequenceHigh=" + sequenceHigh.size() + ", sequenceLow=" + sequenceLow.size() + "]";
		}

	}

	public static class Pwd {
		public String startTime;
		public String endTime;
		public int startHour; // 选一个密码开始时间
		public int endHour; // 选一个密码结束时间[只在常规密码下有效]
		public int type = 4;// 随机密码功能类型(1常规密码,2单次密码,3永久密码,4清空密码,5循环密码)
		public int loopStrategy = 8;// 循环策略(1周一循环,2周二循环,3周三循环,4周四循环,5周五循环,6周六循环,7周天循环,8工作日循环,9周末循环,10每日循环)
		public int loopEndPoint = 21;// 策略，

		public String radPwd;
		public String aesPwd;
	}

}
